home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / ftpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  19.8 KB  |  836 lines

  1. /* FTP Server state machine - see RFC 959 */
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <time.h>
  5. #ifdef    __TURBOC__
  6. #include <io.h>
  7. #include <dir.h>
  8. #endif
  9. #ifdef    AMIGA
  10. #include "amiga/stat.h"
  11. #else
  12. #include <sys/stat.h>
  13. #endif
  14. #include "global.h"
  15. #include "config.h"
  16. #include "mbuf.h"
  17. #include "socket.h"
  18. #include "ftp.h"
  19. #include "ftpserv.h"
  20. #include "proc.h"
  21. #include "dirutil.h"
  22. #include "cmdparse.h"
  23. #include "commands.h"
  24. #include "files.h"
  25.  
  26. static void ftpserv __ARGS((int s,void *unused,void *p));
  27. static int pport __ARGS((struct sockaddr_in *sock,char *arg));
  28. static void ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  29. static int sendit __ARGS((struct ftpserv *ftp,char *command,char *file));
  30. static int recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  31. static void ftp_redundant __ARGS((struct ftpserv *ftp));
  32.  
  33. int timewind __ARGS((int argc,char *argv[],void *p));
  34. int doftptdisc __ARGS((int argc, char *argv[], void *p));
  35.  
  36. /* Command table */
  37. static char *commands[] = {
  38.     "user",
  39.     "acct",
  40.     "pass",
  41.     "type",
  42.     "list",
  43.     "cwd",
  44.     "dele",
  45.     "name",
  46.     "quit",
  47.     "retr",
  48.     "stor",
  49.     "port",
  50.     "nlst",
  51.     "pwd",
  52.     "xpwd",            /* For compatibility with 4.2BSD */
  53.     "mkd ",
  54.     "xmkd",            /* For compatibility with 4.2BSD */
  55.     "xrmd",            /* For compatibility with 4.2BSD */
  56.     "rmd ",
  57.     "stru",
  58.     "mode",
  59.     NULLCHAR
  60. };
  61.  
  62. /* Response messages */
  63.  
  64. static char binwarn[]   = "100 Warning: File %s appears to be BINARY\n";
  65. static char sending[]   = "150 Open %s for %s %s (%ld Bytes)\n";
  66. static char recving[]   = "150 Open %s for %s %s\n";
  67.  
  68. static char typeok[]    = "200 Type %s OK\n";
  69. static char mkdok[]     = "200 MKD ok\n";
  70. static char portok[]    = "200 Port command okay\n";
  71. static char okay[]      = "200 Ok\n";
  72. static char banner[]    = "220 %s FTP Ready - v%s\n";
  73. static char bye[]       = "221 Goodbye!\n";
  74. static char rxok[]      = "226 File received OK\n";
  75. static char txok[]      = "226 File sent OK\n";
  76. static char logged[]    = "230 %s Logged in, %s\n";
  77. static char loggeda[]   = "230 %s Logged in as anonymous, %s\n";
  78. static char deleok[]    = "250 File deleted\n";
  79. static char pwdmsg[]    = "257 \"%s\" is current directory\n";
  80.  
  81. static char givepass[]  = "331 Enter Password\n";
  82. static char givepasa[]  = "331 Please enter your email address '<user-id>@<host-name>'\n";
  83.  
  84. static char lowmem[]    = "421 System overloaded, try again later\n";
  85. static char noconn[]    = "425 Data connection reset\n";
  86.  
  87. static char unsupp[]    = "500 Unsupported command or option\n";
  88. static char badcmd[]    = "500 Unknown command\n";
  89. static char only8[]     = "501 Only logical bytesize 8 supported\n";
  90. static char badtype[]   = "501 Unknown type \"%s\"\n";
  91. static char badport[]   = "501 Bad port syntax\n";
  92. static char unimp[]     = "502 Command not yet implemented\n";
  93. static char userfirst[] = "503 Login with USER first.\n";
  94. static char notlog[]    = "530 Please log in with USER and PASS\n";
  95. static char noperm[]    = "550 Permission denied\n";
  96. static char cantopen[]  = "550 Can't read file \"%s\": %s\n";
  97. static char delefail[]  = "550 Delete failed: %s\n";
  98. static char writerr[]   = "552 Write error: %s\n";
  99. static char nodir[]     = "553 Can't read directory \"%s\": %s\n";
  100. static char cantmake[]  = "553 Can't create \"%s\": %s\n";
  101. static char notyet[]    = "555 Try Later : Access '%2d:00-%2d:59 %s' only\n";
  102.  
  103. static int Sftp = -1;    /* Prototype socket for service */
  104.  
  105. extern char *curftwin;
  106. int tt1, tt2, tnw;
  107.  
  108. #ifdef FTPTDISC
  109. int32 Ftptdiscinit = 0;
  110.  
  111. /* Set ftp redundancy timer */
  112. int
  113. doftptdisc(argc,argv,p)
  114. int argc;
  115. char *argv[];
  116. void *p;
  117. {
  118.     return setlong(&Ftptdiscinit,"Ftp redundancy timer (sec)",argc,argv);
  119. }
  120.  
  121. static void
  122. ftp_redundant(ftp)
  123. struct ftpserv *ftp;
  124. {
  125.     /* Clean up */
  126.     shutdown(ftp->control,2);
  127.     mainlog(ftp->control,"close FTP - Redundant");
  128.     close_s(ftp->control);
  129.     if(ftp->data != -1){
  130.         shutdown(ftp->data,2);
  131.         close_s(ftp->data);
  132.         ftp->data = -1;
  133.     }
  134.     return;
  135. }
  136. #endif
  137.  
  138. /* Start up FTP service */
  139. int ftpstart(argc,argv,p)
  140. int argc;
  141. char *argv[];
  142. void *p;
  143. {
  144.     struct sockaddr_in lsocket;
  145.     int s;
  146.  
  147.     if(Sftp != -1){
  148.         /* Already running! */
  149.         freeargs(argc,argv);
  150.         return 0;
  151.     }
  152.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  153.     chname(Curproc,"FTP listener");
  154.  
  155.     lsocket.sin_family = AF_INET;
  156.     lsocket.sin_addr.s_addr = INADDR_ANY;
  157.     if(argc < 2)
  158.         lsocket.sin_port = IPPORT_FTP;
  159.     else
  160.         lsocket.sin_port = atoi(argv[1]);
  161.  
  162.     freeargs(argc,argv);
  163.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  164.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  165.     listen(Sftp,1);
  166.     for(;;){
  167.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  168.             break;    /* Service is shutting down */
  169.  
  170.         if(availmem() < Memthresh){
  171.             usprintf(s,lowmem);
  172.             shutdown(s,1);
  173.         } else {
  174.             /* Spawn a server */
  175.             newproc("ftpserv",2048,ftpserv,s,NULL,NULL);
  176.         }
  177.     }
  178.     return 0;
  179. }
  180.  
  181. static void ftpserv(s,unused,p)
  182. int s;    /* Socket with user connection */
  183. void *unused;
  184. void *p;
  185. {
  186.     struct ftpserv ftp;
  187.     char **cmdp,buf[512],buf2[77],*arg,*cp,*file,*mode;
  188.     int cnt,i;
  189.     struct sockaddr_in socket;
  190.     FILE *fp;
  191.  
  192.     memset((char *)&ftp,0,sizeof(ftp));    /* Start with clear slate */
  193.     ftp.data = -1;
  194.  
  195.     sockowner(s,Curproc);        /* We own it now */
  196.     ftp.control = s;
  197.     /* Set default data port */
  198.     i = SOCKSIZE;
  199.     getpeername(s,(char *)&socket,&i);
  200.     socket.sin_port = IPPORT_FTPD;
  201.     ASSIGN(ftp.port,socket);
  202.  
  203. #ifdef FTPTDISC
  204.     /* Set the timeout timer - WG7J */
  205.     set_timer(&ftp.tdisc,Ftptdiscinit * 1000L);
  206.     ftp.tdisc.func = ftp_redundant;
  207.     ftp.tdisc.arg = &ftp;
  208.     start_timer(&ftp.tdisc);
  209. #endif
  210.  
  211.     mainlog(ftp.control,"open FTP");
  212.     sprintf(buf2,"%s/FTP.Before",SignOn);
  213.     if((fp = fopen(buf2,READ_TEXT)) != NULLFILE) {
  214.         sendfile(fp,s,ASCII_TYPE,0);
  215.         fclose(fp);
  216.     }
  217.  
  218.     usprintf(s,banner,Hostname,Version);
  219. loop:    if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  220.         /* He closed on us */
  221.         goto finish;
  222.     }
  223. #ifdef FTPTDISC
  224.     /* Reset the timeout timer - WG7J */
  225.     start_timer(&ftp.tdisc);
  226. #endif
  227.     if(cnt == 0){
  228.         /* Can't be a legal FTP command */
  229.         usprintf(ftp.control,badcmd);
  230.         goto loop;
  231.     }    
  232.     rip(buf);
  233.     /* Translate entire buffer to lower case */
  234.     for(cp = buf;*cp != '\0';cp++)
  235.         *cp = tolower(*cp);
  236.     /* Find command in table; if not present, return syntax error */
  237.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  238.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  239.             break;
  240.     if(*cmdp == NULLCHAR){
  241.         usprintf(ftp.control,badcmd);
  242.         goto loop;
  243.     }
  244.     /* Allow only USER, PASS, QUIT before logging in */
  245.     if(ftp.cd == NULLCHAR || ftp.path == NULLCHAR){
  246.         switch(cmdp-commands){
  247.         case USER_CMD:
  248.         case PASS_CMD:
  249.         case QUIT_CMD:
  250.             break;
  251.         default:
  252.             usprintf(ftp.control,notlog);
  253.             goto loop;
  254.         }
  255.     }
  256.     arg = &buf[strlen(*cmdp)];
  257.     while(*arg == ' ')
  258.         arg++;
  259.  
  260.     /* Execute specific command */
  261.     switch(cmdp-commands){
  262.     case USER_CMD:
  263.         if(timewind(NULL,NULLCHAR,NULL)) {
  264.             usprintf(ftp.control,notyet,tt1,tt2,
  265.                 ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  266.             goto finish;
  267.         }
  268.         free(ftp.username);
  269.         ftp.username = strdup(arg);
  270.         if(stricmp("anonymous",ftp.username) == 0)
  271.             usprintf(ftp.control,givepasa);
  272.         else
  273.             usprintf(ftp.control,givepass);
  274.         break;
  275.     case TYPE_CMD:
  276.         switch(arg[0]){
  277.         case 'A':
  278.         case 'a':    /* Ascii */
  279.             ftp.type = ASCII_TYPE;
  280.             usprintf(ftp.control,typeok,arg);
  281.             break;
  282.         case 'l':
  283.         case 'L':
  284.             while(*arg != ' ' && *arg != '\0')
  285.                 arg++;
  286.             if(*arg == '\0' || *++arg != '8'){
  287.                 usprintf(ftp.control,only8);
  288.                 break;
  289.             }
  290.             ftp.type = LOGICAL_TYPE;
  291.             ftp.logbsize = 8;
  292.             usprintf(ftp.control,typeok,arg);
  293.             break;
  294.         case 'B':
  295.         case 'b':    /* Binary */
  296.         case 'I':
  297.         case 'i':    /* Image */
  298.             ftp.type = IMAGE_TYPE;
  299.             usprintf(ftp.control,typeok,arg);
  300.             break;
  301.         default:    /* Invalid */
  302.             usprintf(ftp.control,badtype,arg);
  303.             break;
  304.         }
  305.         break;
  306.     case QUIT_CMD:
  307.         usprintf(ftp.control,bye);
  308.         goto finish;
  309.     case RETR_CMD:
  310.         if(timewind(NULL,NULLCHAR,NULL)) {
  311.             usprintf(ftp.control,notyet,tt1,tt2,
  312.                 ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  313.             goto finish;
  314.         }
  315.         file = pathname(ftp.cd,arg);
  316.         switch(ftp.type){
  317.         case IMAGE_TYPE:
  318.         case LOGICAL_TYPE:
  319.             mode = READ_BINARY;
  320.             break;
  321.         case ASCII_TYPE:
  322.             mode = READ_TEXT;
  323.             break;
  324.         }
  325.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  326.              usprintf(ftp.control,noperm);
  327.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  328.             usprintf(ftp.control,cantopen,file,sys_errlist[errno]);
  329.         } else {
  330.             mainlog(ftp.control,"RETR %s",file);
  331.             if(ftp.type == ASCII_TYPE && isbinary(ftp.fp)){
  332.                 usprintf(ftp.control,binwarn,file);
  333.             }
  334.             sendit(&ftp,"RETR",file);
  335.         }
  336.         free(file);
  337.         break;
  338.     case STOR_CMD:
  339.         if(timewind(NULL,NULLCHAR,NULL)) {
  340.             usprintf(ftp.control,notyet,tt1,tt2,
  341.                 ((p = getenv("TZ")) == NULL) ? "GMT" : p);
  342.             goto finish;
  343.         }
  344.         file = pathname(ftp.cd,arg);
  345.         switch(ftp.type){
  346.         case IMAGE_TYPE:
  347.         case LOGICAL_TYPE:
  348.             mode = WRITE_BINARY;
  349.             break;
  350.         case ASCII_TYPE:
  351.             mode = WRITE_TEXT;
  352.             break;
  353.         }
  354.         if(!permcheck(ftp.path,ftp.perms,STOR_CMD,file)){
  355.              usprintf(ftp.control,noperm);
  356.         } else if((ftp.fp = fopen(file,mode)) == NULLFILE){
  357.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  358.         } else {
  359.             mainlog(ftp.control,"STOR %s",file);
  360.             recvit(&ftp,"STOR",file);
  361.         }
  362.         free(file);
  363.         break;
  364.     case PORT_CMD:
  365.         if(pport(&ftp.port,arg) == -1){
  366.             usprintf(ftp.control,badport);
  367.         } else {
  368.             usprintf(ftp.control,portok);
  369.         }
  370.         break;
  371.     case LIST_CMD:
  372.         file = pathname(ftp.cd,arg);
  373.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  374.              usprintf(ftp.control,noperm);
  375.         } else if((ftp.fp = dir(file,1)) == NULLFILE){
  376.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  377.         } else {
  378.             sendit(&ftp,"LIST",file);
  379.         }
  380.         free(file);
  381.         break;
  382.     case NLST_CMD:
  383.         file = pathname(ftp.cd,arg);
  384.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  385.              usprintf(ftp.control,noperm);
  386.         } else if((ftp.fp = dir(file,0)) == NULLFILE){
  387.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  388.         } else {
  389.             sendit(&ftp,"NLST",file);
  390.         }
  391.         free(file);
  392.         break;
  393.     case CWD_CMD:
  394.         file = pathname(ftp.cd,arg);
  395.         if(!permcheck(ftp.path,ftp.perms,RETR_CMD,file)){
  396.              usprintf(ftp.control,noperm);
  397.             free(file);
  398.         } else if(access(file,0) == 0){    /* See if it exists */
  399.             /* Succeeded, record in control block */
  400.             free(ftp.cd);
  401.             ftp.cd = file;
  402.             usprintf(ftp.control,pwdmsg,file);
  403.         } else {
  404.             /* Failed, don't change anything */
  405.             usprintf(ftp.control,nodir,file,sys_errlist[errno]);
  406.             free(file);
  407.         }
  408.         break;
  409.     case XPWD_CMD:
  410.     case PWD_CMD:
  411.         usprintf(ftp.control,pwdmsg,ftp.cd);
  412.         break;
  413.     case ACCT_CMD:        
  414.         usprintf(ftp.control,unimp);
  415.         break;
  416.     case DELE_CMD:
  417.         file = pathname(ftp.cd,arg);
  418.         if(!permcheck(ftp.path,ftp.perms,DELE_CMD,file)){
  419.              usprintf(ftp.control,noperm);
  420.         } else if(unlink(file) == 0){
  421.             mainlog(ftp.control,"DELE %s",file);
  422.             usprintf(ftp.control,deleok);
  423.         } else {
  424.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  425.         }
  426.         free(file);
  427.         break;
  428.     case PASS_CMD:
  429.         if(ftp.username == NULLCHAR)
  430.             usprintf(ftp.control,userfirst);
  431.         else
  432.             ftplogin(&ftp,arg);            
  433.         break;
  434.     case XMKD_CMD:
  435.     case MKD_CMD:
  436.         file = pathname(ftp.cd,arg);
  437.         if(!permcheck(ftp.path,ftp.perms,MKD_CMD,file)){
  438.             usprintf(ftp.control,noperm);
  439.         } else if(mkdir(file) == 0){
  440.             mainlog(ftp.control,"MKD %s",file);
  441.             usprintf(ftp.control,mkdok);
  442.         } else {
  443.             usprintf(ftp.control,cantmake,file,sys_errlist[errno]);
  444.         }
  445.         free(file);
  446.         break;
  447.     case XRMD_CMD:
  448.     case RMD_CMD:
  449.         file = pathname(ftp.cd,arg);
  450.         if(!permcheck(ftp.path,ftp.perms,RMD_CMD,file)){
  451.              usprintf(ftp.control,noperm);
  452.         } else if(rmdir(file) == 0){
  453.             mainlog(ftp.control,"RMD %s",file);
  454.             usprintf(ftp.control,deleok);
  455.         } else {
  456.             usprintf(ftp.control,delefail,sys_errlist[errno]);
  457.         }
  458.         free(file);
  459.         break;
  460.     case STRU_CMD:
  461.         if(tolower(arg[0]) != 'f')
  462.             usprintf(ftp.control,unsupp);
  463.         else
  464.             usprintf(ftp.control,okay);
  465.         break;
  466.     case MODE_CMD:
  467.         if(tolower(arg[0]) != 's')
  468.             usprintf(ftp.control,unsupp);
  469.         else
  470.             usprintf(ftp.control,okay);
  471.         break;
  472.     }
  473.     goto loop;
  474. finish:
  475.  
  476. #ifdef FTPTDISC
  477.     stop_timer(&ftp.tdisc);
  478. #endif
  479.  
  480.     mainlog(ftp.control,"close FTP");
  481.     /* Clean up */
  482.     close_s(ftp.control);
  483.     if(ftp.data != -1)
  484.         close_s(ftp.data);
  485.     if(ftp.fp != NULLFILE)
  486.         fclose(ftp.fp);
  487.     free(ftp.username);
  488.     free(ftp.path);
  489.     free(ftp.cd);
  490. }
  491.  
  492. /* Shut down FTP server */
  493. int ftp0(argc,argv,p)
  494. int argc;
  495. char *argv[];
  496. void *p;
  497. {
  498.     close_s(Sftp);
  499.     Sftp = -1;
  500.     return 0;
  501. }
  502.  
  503. static int pport(sock,arg)
  504. struct sockaddr_in *sock;
  505. char *arg;
  506. {
  507.     int32 n;
  508.     int i;
  509.  
  510.     n = 0;
  511.     for(i=0;i<4;i++){
  512.         n = atoi(arg) + (n << 8);
  513.         if((arg = strchr(arg,',')) == NULLCHAR)
  514.             return -1;
  515.         arg++;
  516.     }
  517.     sock->sin_addr.s_addr = n;
  518.     n = atoi(arg);
  519.     if((arg = strchr(arg,',')) == NULLCHAR)
  520.         return -1;
  521.     arg++;
  522.     n = atoi(arg) + (n << 8);
  523.     sock->sin_port = n;
  524.     return 0;
  525. }
  526.  
  527. /* Subroutine for logging in the user whose name is name and
  528.    password is pass.  The buffer path should be long enough to
  529.    keep a line from the userfile.  If pwdignore is true, the
  530.    password check will be overridden.  The return value is the
  531.    permissions field or -1 if the login failed.  Path is set to
  532.    point at the path field, and pwdignore will be true if no
  533.    particular password was needed for this user.
  534.  */
  535. int userlogin(name,pass,path,len,pwdignore)
  536. char *name;
  537. char *pass;
  538. char **path;
  539. int len;            /* Length of buffer pointed at by *path */
  540. int *pwdignore;
  541. {
  542.     char *cp,*cp1;
  543.     FILE *fp;
  544.     char *anonymous = NULLCHAR;
  545.     int anony, perm;
  546.  
  547.     if((fp = fopen(Userfile,READ_TEXT)) == NULLFILE)
  548.         /* Userfile doesn't exist */
  549.         return -1;
  550.     while(fgets(*path,len,fp),!feof(fp)){
  551.         if(*path[0] == '#')
  552.             continue;    /* Comment */
  553.         if((cp = strchr(*path,' ')) == NULLCHAR)
  554.             /* Bogus entry */
  555.             continue;
  556.         *cp++ = '\0';        /* Now points to password */
  557.         if(stricmp(name,*path) == 0)
  558.             break;        /* Found user name */
  559.         if(stricmp("anonymous",*path) == 0)
  560.             anonymous = strdup(cp); /* remember anon entry */
  561.     }
  562.     if((anonymous == NULLCHAR) && (feof(fp))) {
  563.         /* User not in file, nor was anonymous */
  564.         fclose(fp);
  565.         return -1;
  566.     }
  567.      if(feof(fp)){
  568.         /* restore anonymous */
  569.         strcpy(cp = *path, anonymous);
  570.     }
  571.     fclose(fp);
  572.     /* Look for space after password field in file */
  573.     if((cp1 = strchr(cp,' ')) == NULLCHAR)
  574.         /* Invalid file entry */
  575.         return -1;
  576.     *cp1++ = '\0';    /* Now points to path field */
  577.     anony = *pwdignore;
  578.     if(strcmp(cp,"*") == 0)
  579.         anony = 1;    /* User ID is password-free */
  580.     if(!anony && strcmp(cp,pass) != 0)
  581.         /* Password required, but wrong one given */
  582.         return -1;
  583.     if((cp = strchr(cp1,' ')) == NULLCHAR)
  584.         /* Permission field missing */
  585.         return -1;
  586.     *cp++ = '\0';    /* now points to permission field */
  587.     perm = atoi(cp);
  588. /*
  589.  *  Well, on the Amiga, a file can be referenced by many names:
  590.  *  device names (DF0:) or volume names (My_Disk:).  This hunk of code
  591.  *  passed the pathname specified in the ftpusers file, and gets the
  592.  *  absolute path copied into the user's buffer.  We really should just
  593.  *  allocate the buffer and return a pointer to it, since the caller
  594.  *  really doesn't have a good idea how long the path string is..
  595.  */
  596.     cp1 = pathname("", cp1);
  597.     if (cp1)
  598.         strcpy(*path, cp1);
  599.     else
  600.         **path = '\0';
  601.     free(cp1);
  602.     *pwdignore = anony;
  603.     /* Finally return the permission bits */
  604.     return perm;
  605. }
  606.     
  607. /* Attempt to log in the user whose name is in ftp->username and password
  608.  * in pass
  609.  */
  610. static void ftplogin(ftp,pass)
  611. struct ftpserv *ftp;
  612. char *pass;
  613. {
  614.     long t;
  615.     char *path,buf2[77],*cp,*cp1;
  616.     int anony = 0;
  617.     FILE *fp;
  618.  
  619.     path = mallocw(200);
  620.     if((ftp->perms = userlogin(ftp->username,pass,&path,200,&anony))
  621.        == -1){
  622.         usprintf(ftp->control,noperm);
  623.         free(path);
  624.         return;
  625.     }
  626.     /* Set up current directory and path prefix */
  627.     ftp->cd = path;
  628.     ftp->path = strdup(path);
  629.  
  630.     sprintf(buf2,"%s/FTP.After",SignOn);
  631.     if((fp = fopen(buf2,READ_TEXT)) != NULLFILE) {
  632.         sendfile(fp,ftp->control,ASCII_TYPE,0);
  633.         fclose(fp);
  634.     }
  635.  
  636.     time(&t);
  637.     cp = ctime(&t);
  638.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  639.         *cp1 = '\0';
  640.  
  641.     if(!anony) {
  642.         usprintf(ftp->control,logged,ftp->username,cp);
  643.         mainlog(ftp->control,"%s logged in",ftp->username);
  644.     } else {
  645.         usprintf(ftp->control,loggeda,
  646.             strcmp(ftp->username,"anonymous") ? 
  647.             ftp->username : "",cp);
  648.         mainlog(ftp->control,"%s logged in, ID %s",ftp->username,pass);
  649.     }
  650. }        
  651.  
  652. /* Return 1 if the file operation is allowed, 0 otherwise */
  653. int permcheck(path,perms,op,file)
  654. char *path;
  655. int perms;
  656. int op;
  657. char *file;
  658. {
  659.     if(file == NULLCHAR || path == NULLCHAR)
  660.         return 0;    /* Probably hasn't logged in yet */
  661.  
  662.     /* The target file must be under the user's allowed search path */
  663.     if(strncmp(file,path,strlen(path)) != 0)
  664.         return 0;
  665.  
  666.     switch(op){
  667.     case RETR_CMD:
  668.         /* User must have permission to read files */
  669.         if(perms & FTP_READ)
  670.             return 1;
  671.         return 0;
  672.     case DELE_CMD:
  673.     case RMD_CMD:
  674.         /* User must have permission to (over)write files */
  675.         if(perms & FTP_WRITE)
  676.             return 1;
  677.         return 0;
  678.     case STOR_CMD:
  679.     case MKD_CMD:
  680.         /* User must have permission to (over)write files, or permission
  681.          * to create them if the file doesn't already exist
  682.          */
  683.         if(perms & FTP_WRITE)
  684.             return 1;
  685.         if(access(file,2) == -1 && (perms & FTP_CREATE))
  686.             return 1;
  687.         return 0;
  688.     }
  689.     return 0;    /* "can't happen" -- keep lint happy */
  690. }
  691.  
  692. static int sendit(ftp,command,file)
  693. struct ftpserv *ftp;
  694. char *command;
  695. char *file;
  696. {
  697.     long total;
  698.     struct sockaddr_in dport;
  699.     struct stat stb;
  700.  
  701.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  702.     dport.sin_family = AF_INET;
  703.     dport.sin_addr.s_addr = INADDR_ANY;
  704.     dport.sin_port = IPPORT_FTPD;
  705.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  706.     stat(file,&stb);
  707.     usprintf(ftp->control,sending,file,ftp->type ? "BINARY" : "ASCII",command,stb.st_size);
  708.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  709.         fclose(ftp->fp);
  710.         ftp->fp = NULLFILE;
  711.         close_s(ftp->data);
  712.         ftp->data = -1;
  713.         usprintf(ftp->control,noconn);
  714.         return -1;
  715.     }
  716. #ifdef FTPTDISC
  717.     /* Turn of the timeout timer here, some ftp's could
  718.      * take a long time with sloooow packet channels - WG7J
  719.      */
  720.     stop_timer(&ftp->tdisc);
  721. #endif
  722.     /* Do the actual transfer */
  723.     total = sendfile(ftp->fp,ftp->data,ftp->type,0);
  724.  
  725. #ifdef FTPTDISC
  726.     /* And turn it back on now */
  727.     start_timer(&ftp->tdisc);
  728. #endif
  729.     if(total == -1){
  730.         /* An error occurred on the data connection */
  731.         usprintf(ftp->control,noconn);
  732.         shutdown(ftp->data,2);    /* Blow away data connection */
  733.     } else {
  734.         usprintf(ftp->control,txok);
  735.     }
  736.     fclose(ftp->fp);
  737.     ftp->fp = NULLFILE;
  738.     close_s(ftp->data);
  739.     ftp->data = -1;
  740.     if(total == -1)
  741.         return -1;
  742.     else
  743.         return 0;
  744. }
  745.  
  746. static int recvit(ftp,command,file)
  747. struct ftpserv *ftp;
  748. char *command;
  749. char *file;
  750. {
  751.     struct sockaddr_in dport;
  752.     long total;
  753.  
  754.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  755.     dport.sin_family = AF_INET;
  756.     dport.sin_addr.s_addr = INADDR_ANY;
  757.     dport.sin_port = IPPORT_FTPD;
  758.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  759.     usprintf(ftp->control,recving,file,ftp->type ? "BINARY" : "ASCII",command);
  760.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  761.         fclose(ftp->fp);
  762.         ftp->fp = NULLFILE;
  763.         close_s(ftp->data);
  764.         ftp->data = -1;
  765.         usprintf(ftp->control,noconn);
  766.         return -1;
  767.     }
  768. #ifdef FTPTDISC
  769.     /* Turn of the timeout timer here; some ftp's could
  770.      * take a long time with sloooow packet channels - WG7J
  771.      */
  772.     stop_timer(&ftp->tdisc);
  773. #endif
  774.  
  775.     /* Do the actual transfer */
  776.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  777.  
  778. #ifdef FTPTDISC
  779.     /* And turn it back on now */
  780.     start_timer(&ftp->tdisc);
  781. #endif
  782.  
  783.     if(total == -1) {
  784.         /* An error occurred while writing the file */
  785.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  786.         shutdown(ftp->data,2);    /* Blow it away */
  787.     } else {
  788.         usprintf(ftp->control,rxok);
  789.         close_s(ftp->data);
  790.     }
  791.     ftp->data = -1;
  792.     fclose(ftp->fp);
  793.     ftp->fp = NULLFILE;
  794.     if(total == -1)
  795.         return -1;
  796.     else
  797.         return 0;
  798. }
  799.  
  800. /* This checks the current time is in a preset Time-Window before
  801.    allowing a user to login */
  802. int timewind(argc,argv,p)
  803. int argc;
  804. char *argv[];
  805. void *p;
  806. {
  807.     char *now;
  808.     long t;
  809.     char *t1, *t2;
  810.  
  811.     t1 = strdup(curftwin);
  812.     *(t1 + 2) = '\0';
  813.     tt1 = atoi(t1);
  814.  
  815.     t2 = strdup(curftwin+2);
  816.     *(t2 + 2) = '\0';
  817.     tt2 = atoi(t2);
  818.  
  819.     time(&t);
  820.     now = ctime(&t) + 11;
  821.     *(now + 2) = '\0';
  822.     tnw = atoi(now);
  823.  
  824.     if(tt1 > tt2) {
  825.         if(((tnw >= tt1) && (tnw <= 23)) ||
  826.            ((tnw <= tt2) && (tnw >= 0)))
  827.             return 0;        /* right in time */
  828.     } else {
  829.         if((tnw >= tt1) && (tnw <= tt2))
  830.             return 0;        /* right in time */
  831.     }
  832.  
  833.     return 1;
  834. }
  835.  
  836.